package crudextend

import (
	"container/list"
	"fmt"
	"iot-base/common/common"
	"iot-base/common/dbobj"
	"iot-base/common/innermq"
	"iot-base/common/logger"
	"iot-base/common/notify"

	redis "iot-base/common/redis"
	"reflect"
	"strconv"
	"sync"
	"time"
)

//CrudMsg 注入消息
type CrudMsg struct {
	Action   string //"update"/"delete"/"post"/
	TModelID string
	MsgBase
	PThing        *dbobj.Thing
	PStation      *dbobj.Station
	PThingStation *dbobj.ThingStation
	PThingParams  *[]dbobj.ThingParam
}

//CrudMsgResp 注入消息回应
type CrudMsgResp struct {
	Err      error
	Continue bool
	MsgBase
	PThing        *dbobj.Thing
	PStation      *dbobj.Station
	PThingStation *dbobj.ThingStation
	PThingParams  *[]dbobj.ThingParam
}

//RawMsg
type RawMsg struct {
	Action string //"update"/"delete"/"post"/
	Infos  []map[string]interface{}
	Info   map[string]interface{}
}

//CrudMsg 注入消息
type StationMsg struct {
	TModelID string
	MsgBase
	StationID string
	RawMsg
}

//StationMsgResp 注入消息回应
type StationMsgResp struct {
	Err      error
	Continue bool
	Seq      int64
	Infos    []map[string]interface{}
	Info     map[string]interface{}
}

func makeID(tmodelID string) string {
	return "extend." + tmodelID + ".modify"
}

func makeStationID(tmodelID string) string {
	return "station.extend." + tmodelID + ".modify"
}
func makeHTTPID(prefix string) string {
	return "extend." + prefix + ".http"
}

var listRegisters *list.List
var lockList sync.RWMutex

func timerTask() {
	timer := time.NewTimer(4 * time.Minute)
	for {
		timer.Reset(4 * time.Minute) // 这里复用了 timer
		select {
		case <-timer.C:
			var duration_Minute time.Duration = 5 * time.Minute
			lockList.RLock()
			for i := listRegisters.Front(); i != nil; i = i.Next() {
				id, ok := i.Value.(string)
				if ok {
					redis.Set(id, "1", duration_Minute)
				}

			}
			lockList.RUnlock()
		}
	}
}

func init() {
	listRegisters = list.New()
	go timerTask()
}

//RegisterDveModify 注册
func registerModifyImpl(makeIDfun func(id string) string, tmodelID string, msg interface{},
	callback func(msg interface{}) interface{}) {
	logger.SLog.Info("register modify-----------", tmodelID)
	mid := makeIDfun(tmodelID)
	lockList.Lock()
	listRegisters.PushBack(mid + ".extend")
	defer lockList.Unlock()
	var duration_Minute time.Duration = 5 * time.Minute
	redis.Set(mid+".extend", "1", duration_Minute)
	notify.SubMsg(true, mid, msg, func(t string, b interface{}) {
		fmt.Println("found msg-------------------------------")
		pMsg, ok := b.(IMsgBase)
		if ok && callback != nil {
			fmt.Println("found msg---------------------callback----------")
			presult := callback(b)
			//presult := &result
			seq := pMsg.GetSeq()
			if presult != nil {
				fmt.Println("found msg---------------------result ok----------")
				id := t + ".resp." + strconv.FormatInt(seq, 10)
				notify.PubMsg(true, id, presult)
			}

		}
	})
}

//GetExtendResult 获取扩展模块对修改的处理意见
func GetExtendResult(tmodelID string, pMsg *CrudMsg) *CrudMsgResp {
	//mid := makeID(tmodelID)
	result := getExtendResultImpl(makeID, tmodelID, pMsg, &CrudMsgResp{})
	if result != nil {
		pResult, ok := result.(*CrudMsgResp)
		if ok {
			return pResult
		}
	}
	return nil
}

/*
pMsg, ok := b.(*CrudMsg)
		if ok && callback != nil {
			result := callback(pMsg)
			result.Seq = pMsg.Seq
			id := t + ".resp." + strconv.FormatInt(pMsg.Seq, 10)
			notify.PubMsg(true, id, &result)
		}*/

type IMsgBase interface {
	GetSeq() int64
	SetSeq(seq int64)
}

type MsgBase struct {
	Seq int64
}

func (self MsgBase) GetSeq() int64 {
	return self.Seq
}

func (self *MsgBase) SetSeq(seq int64) {
	self.Seq = seq
}

//RegisterDveModify 注册
func RegisterDveModify(tmodelID string, callback func(msg *CrudMsg) CrudMsgResp) {
	registerModifyImpl(makeID, tmodelID, &CrudMsg{}, func(tmsg interface{}) interface{} {
		pMsg, ok := tmsg.(*CrudMsg)
		if ok && callback != nil {
			return callback(pMsg)
		}
		return nil
	})
}

//GetExtendResult 获取扩展模块对修改的处理意见
func getExtendResultImpl(makeIDfun func(id string) string, tmodelID string, pMsg IMsgBase, resp interface{}) interface{} {
	mid := makeIDfun(tmodelID)
	value, err := redis.Get(mid + ".extend").Result()

	if err == nil && value == "1" {
		logger.SLog.Info("send msg to queen------------", mid)
		seq, _ := common.GetSnowflakeId()
		pMsg.SetSeq(seq)
		notify.PubMsg(true, mid, pMsg)
		//var resp CrudMsgResp
		var result interface{}
		innermq.WaitforMsgSync(mid+".resp."+strconv.FormatInt(pMsg.GetSeq(), 10), resp,
			2*time.Minute, func(t string, body interface{}) {
				result = body
			}, nil)
		return result
	}
	return nil
}

//GetStationActiontResult 获取行业模块关于站点操作的意见
func GetStationActiontResult(action string, stationMoldelID string, stationID string, items []map[string]interface{}) *StationMsgResp {
	pmsg := &StationMsg{
		StationID: stationID,
		RawMsg: RawMsg{
			Action: action,
			Infos:  items,
		},
	}
	result := getExtendResultImpl(makeStationID, stationMoldelID, pmsg, &StationMsgResp{})
	if result != nil {
		pResult, ok := result.(*StationMsgResp)
		if ok {
			return pResult
		}
	}
	return nil
}

//HTTPMsg http命令
type HTTPMsg struct {
	QueryMap map[string]string
	RawMsg
	MsgBase
}

//HTTPMsgResp 回应结果
type HTTPMsgResp struct {
	Err   error
	Seq   int64
	Infos []map[string]interface{}
	Info  map[string]interface{}
}

//RegisterStationAction 注册行业模块关于站点操作的意见
func RegisterStationAction(stationMoldelID string, callback func(msg *StationMsg) StationMsgResp) {
	registerModifyImpl(makeStationID, stationMoldelID, &StationMsg{}, func(tmsg interface{}) interface{} {
		pMsg, ok := tmsg.(*StationMsg)
		if ok && callback != nil {
			return callback(pMsg)
		}
		fmt.Println("-----------msgtype error---------", reflect.TypeOf(tmsg))
		return nil
	})
}

//RegisterStationAction 注册行业模块关于站点操作的意见 具体使用参见evtendobj.go
func RegisterHTTPAction(prefix string, callback func(msg *HTTPMsg) HTTPMsgResp) {
	registerModifyImpl(makeHTTPID, prefix, &HTTPMsg{}, func(tmsg interface{}) interface{} {
		pMsg, ok := tmsg.(*HTTPMsg)
		if ok && callback != nil {
			return callback(pMsg)
		}
		fmt.Println("-----------httptype error---------", reflect.TypeOf(tmsg))
		return nil
	})
}

//GetHTTPResult 获取http结果
func GetHTTPResult(action string, prefix string, queryMap map[string]string, item map[string]interface{},
	items []map[string]interface{}) *HTTPMsgResp {
	pmsg := &HTTPMsg{
		QueryMap: queryMap,
		RawMsg: RawMsg{
			Action: action,
			Infos:  items,
			Info:   item,
		},
	}
	result := getExtendResultImpl(makeHTTPID, prefix, pmsg, &HTTPMsgResp{})
	if result != nil {
		pResult, ok := result.(*HTTPMsgResp)
		if ok {
			return pResult
		}
	}
	return nil
}
